"""
无人机路径规划FastAPI服务
提供RESTful API接口
"""

from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.exception_handlers import RequestValidationError
from fastapi.staticfiles import StaticFiles
from pydantic import ValidationError
import time
import logging
from datetime import datetime
from typing import Dict, Any
import traceback

from models import (
    PathPlanningRequest, 
    PathPlanningResponse, 
    ErrorResponse, 
    HealthResponse,
    ServiceStatus
)
from algorithm import PathPlanner, Node, NoFlyZone

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# 创建FastAPI应用
app = FastAPI(
    title="无人机路径规划API",
    description="基于欧拉路径的无人机路径规划服务，支持禁飞区避让",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

# 添加CORS中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 生产环境中应该设置具体的域名
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 挂载静态文件
app.mount("/static", StaticFiles(directory="static"), name="static")

# 全局异常处理器
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    """处理请求验证错误"""
    logger.error(f"验证错误: {exc.errors()}")
    
    error_details = []
    for error in exc.errors():
        error_details.append({
            "field": " -> ".join(str(x) for x in error["loc"]),
            "message": error["msg"],
            "type": error["type"]
        })
    
    return JSONResponse(
        status_code=422,
        content=ErrorResponse(
            error="ValidationError",
            message="输入数据验证失败",
            detail={"errors": error_details}
        ).dict()
    )

@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
    """处理值错误"""
    logger.error(f"值错误: {str(exc)}")
    return JSONResponse(
        status_code=400,
        content=ErrorResponse(
            error="ValueError",
            message=str(exc)
        ).dict()
    )

@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception):
    """处理通用异常"""
    logger.error(f"未处理的异常: {str(exc)}\n{traceback.format_exc()}")
    return JSONResponse(
        status_code=500,
        content=ErrorResponse(
            error="InternalServerError",
            message="服务器内部错误",
            detail={"exception": str(exc)}
        ).dict()
    )

# API路由
from fastapi.responses import RedirectResponse

@app.get("/")
async def root():
    """根路径 - 重定向到Web界面"""
    return RedirectResponse(url="/static/index.html")

@app.get("/health", response_model=HealthResponse)
async def health_check():
    """健康检查端点"""
    return HealthResponse(
        status=ServiceStatus.HEALTHY,
        version="1.0.0",
        timestamp=datetime.utcnow().isoformat() + "Z"
    )

@app.post("/plan-path", response_model=PathPlanningResponse)
async def plan_path(request: PathPlanningRequest):
    """
    路径规划主接口
    
    根据输入的节点、边和约束条件，生成最优的欧拉路径。
    支持禁飞区避让功能。
    """
    start_time = time.time()
    
    try:
        logger.info(f"开始路径规划: {request.start_node} -> {request.end_node}")
        
        # 创建路径规划器
        planner = PathPlanner()
        
        # 转换输入数据
        nodes = [
            Node(id=node.id, longitude=node.longitude, latitude=node.latitude)
            for node in request.nodes
        ]
        
        edges = [
            (edge.from_node, edge.to_node)
            for edge in request.edges
        ]
        
        no_fly_zones = [
            NoFlyZone(coordinates=zone.coordinates)
            for zone in request.no_fly_zones
        ] if request.no_fly_zones else []
        
        # 执行路径规划
        result = planner.plan_path(
            nodes=nodes,
            edges=edges,
            start=request.start_node,
            end=request.end_node,
            no_fly_zones=no_fly_zones,
            max_match_distance=request.max_match_distance
        )
        
        processing_time = time.time() - start_time
        
        if not result.success:
            logger.error(f"路径规划失败: {result.message}")
            raise ValueError(result.message)
        
        logger.info(f"路径规划成功，耗时: {processing_time:.3f}秒")
        
        # 构建响应
        response = PathPlanningResponse(
            success=True,
            message=result.message,
            path=result.path,
            total_distance=result.total_distance,
            path_details=[
                {
                    "segment": detail["segment"],
                    "from_node": detail["from"],
                    "to_node": detail["to"],
                    "distance": detail["distance"],
                    "edge_type": detail["edge_type"],
                    "from_coord": detail["from_coord"],
                    "to_coord": detail["to_coord"]
                }
                for detail in result.path_details
            ],
            processing_time=round(processing_time, 3)
        )
        
        return response
        
    except Exception as e:
        processing_time = time.time() - start_time
        logger.error(f"路径规划异常: {str(e)}")
        
        return PathPlanningResponse(
            success=False,
            message=f"路径规划失败: {str(e)}",
            processing_time=round(processing_time, 3)
        )

@app.post("/validate-input", response_model=Dict[str, Any])
async def validate_input(request: PathPlanningRequest):
    """
    输入验证端点
    
    验证输入数据的有效性，不执行实际的路径规划。
    用于前端预验证。
    """
    try:
        # 基本验证已通过Pydantic模型完成
        
        # 额外的业务逻辑验证
        node_ids = set(node.id for node in request.nodes)
        
        # 检查图的连通性
        edge_set = set()
        for edge in request.edges:
            edge_set.add((edge.from_node, edge.to_node))
            edge_set.add((edge.to_node, edge.from_node))
        
        # 简单的连通性检查（DFS）
        if len(node_ids) > 1:
            visited = set()
            stack = [request.start_node]
            
            while stack:
                node = stack.pop()
                if node not in visited:
                    visited.add(node)
                    for edge in request.edges:
                        if edge.from_node == node and edge.to_node not in visited:
                            stack.append(edge.to_node)
                        elif edge.to_node == node and edge.from_node not in visited:
                            stack.append(edge.from_node)
            
            if len(visited) != len(node_ids):
                return {
                    "valid": False,
                    "message": "图不连通，存在孤立节点",
                    "unreachable_nodes": list(node_ids - visited)
                }
        
        return {
            "valid": True,
            "message": "输入数据验证通过",
            "statistics": {
                "node_count": len(request.nodes),
                "edge_count": len(request.edges),
                "no_fly_zone_count": len(request.no_fly_zones) if request.no_fly_zones else 0
            }
        }
        
    except Exception as e:
        return {
            "valid": False,
            "message": f"验证过程中出现错误: {str(e)}"
        }

@app.get("/api-info", response_model=Dict[str, Any])
async def api_info():
    """
    API信息端点
    
    返回API的详细信息和使用说明。
    """
    return {
        "api_name": "无人机路径规划API",
        "version": "1.0.0",
        "description": "基于欧拉路径的无人机路径规划服务，支持禁飞区避让",
        "endpoints": {
            "/plan-path": {
                "method": "POST",
                "description": "执行路径规划",
                "input": "PathPlanningRequest",
                "output": "PathPlanningResponse"
            },
            "/validate-input": {
                "method": "POST", 
                "description": "验证输入数据",
                "input": "PathPlanningRequest",
                "output": "验证结果"
            },
            "/health": {
                "method": "GET",
                "description": "健康检查",
                "output": "HealthResponse"
            }
        },
        "features": [
            "欧拉路径生成",
            "最小权完美匹配",
            "禁飞区避让",
            "路径优化",
            "详细路径信息"
        ],
        "algorithms": {
            "eulerian_path": "Hierholzer算法",
            "matching": "NetworkX最小权完美匹配",
            "detour": "边界绕飞算法"
        }
    }

# 启动配置
if __name__ == "__main__":
    import uvicorn
    
    uvicorn.run(
        "api:app",
        host="0.0.0.0",
        port=8000,
        reload=True,
        log_level="info"
    )
